#include <bits/stdc++.h>
using namespace std;

//https://leetcode.cn/problems/maximize-the-number-of-target-nodes-after-connecting-trees-ii/description/

#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/priority_queue.hpp>

#define st first
#define nd second
#define eb emplace_back
#define pb push_back
#define mp make_pair
#define all(v) (v).begin(), (v).end()

using namespace literals;
namespace pd = __gnu_pbds;
namespace rgs = std::ranges;
namespace rs = rgs;
namespace views = std::ranges::views;
namespace vs = views;

using ll = long long;
using ull = unsigned long long;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
template <class T>
using pqueue = priority_queue<T>;
template <class T>
using mqueue = priority_queue<T, vector<T>, greater<T>>;
template <class T>
using pheap = pd::priority_queue<T, less<T>, pd::pairing_heap_tag>;
template <class Key, class T>
using ordered_map = pd::tree<Key, T, less<Key>, pd::rb_tree_tag, pd::tree_order_statistics_node_update>;
template <class Key>
using ordered_set = ordered_map<Key, pd::null_type>;

template <class F>
struct YC {
    F f;
    YC(F&& f): f(std::forward<F>(f)) {}
    template <class... Args>
    decltype(auto) operator()(Args&&... args) {
        return f(*this, std::forward<Args>(args)...);
    }
};

template <class T> requires ( !is_unsigned_v<T> )
constexpr int popcount(T x) { return popcount<make_unsigned_t<T>>(x); }
int lb(auto& a, auto v) { return lower_bound(all(a), v) - a.begin(); }
int ub(auto& a, auto v) { return upper_bound(all(a), v) - a.begin(); }
void sortu(auto& a) { sort(all(a)); a.erase(unique(all(a)), a.end()); }
ll sum(auto& a) { return accumulate(all(a), 0ll); }

template <size_t N>
auto untie(const auto& a) { if constexpr (N == 0) return tuple<>{};
    else return tuple_cat(untie<N - 1>(a), tuple<decltype(a[0])>{a[N - 1]}); }
template <int n = 2>
auto mdshape(const auto& a) { if constexpr (!n) return tuple<>{};
    else return tuple_cat(tuple<int>{a.size()}, mdshape<n - 1>(a[0])); }
template <class T, size_t N, size_t... Ns>
struct _mdarray { auto f() { if constexpr (sizeof...(Ns)) {
            return array<decltype(_mdarray<T, Ns...>().f()), N>{}; } else { return array<T, N>{}; } } };
template <class T, size_t... Ns> using mdarr = decltype(_mdarray<T, Ns...>().f());
template <integral I> auto mdvec(I n, auto... args) { if constexpr (sizeof...(args) == 1) {
return vector(n, args...); } else { return vector(n, mdvec(args...)); } }
auto mdvec(auto& a, size_t n, auto... args) { if constexpr (!sizeof...(args)) {
        return vector(begin(a), begin(a) + n); } else { vector<decltype(mdvec(a[0], args...))> b;
        b.reserve(n); for (size_t i = 0; i < n;) { b.pb(mdvec(a[i++], args...)); } return b; } }
void mdfill(auto& a, size_t n, auto... args) { if constexpr (sizeof...(args) == 1) {
        fill_n(begin(a), n, args...); } else { for (size_t i = 0; i < n;) { mdfill(a[i++], args...); } } }
template <int b = 0> bool in(int x, int y, int n, int m) { return b <= x && x < n && b <= y && y < m; }

mt19937 mrand(random_device{}());

template <class T>
bool mini(T& l, const T& r) { return r < l ? l = r, 1 : 0; }
template <class T>
bool maxi(T& l, const T& r) { return l < r ? l = r, 1 : 0; }

constexpr ll inf = INT_MAX >> 1;
constexpr double eps = 1e-9;

constexpr int N = 1e5 + 10;
constexpr int M = 1000000007; // 998244343;

int lc_init = ([]() {
}(), 0);

void addi(auto& l, auto r) { l = (l + r) % M; }
void addfi(auto& l, auto r) { if ((l += r) >= M) l -= M; }
ll pw(ll e, ll n, ll m = M) { ll r = 1;
    for (; n; n >>= 1, e = e * e % m) { if (n & 1) r = r * e % m; } return r; }

#define eput(...) 218
#line 10
class Solution {
public:
    vector<int> maxTargetNodes(vector<vector<int>>& edges1, vector<vector<int>>& edges2) {
        int n = edges1.size() + 1, m = edges2.size() + 1;
        auto e = mdvec(n, 0, 0);
        for (auto x: edges1)
            e[x[0]].pb(x[1]), e[x[1]].pb(x[0]);
        auto f = mdvec(m, 0, 0);
        for (auto x: edges2)
            f[x[0]].pb(x[1]), f[x[1]].pb(x[0]);
        auto dfs = YC([&](auto& dfs, auto& e, auto& color, int u, int pre) -> void {
            for (auto v: e[u]) {
                if (v == pre) continue;
                color[v] = !color[u];
                dfs(e, color, v, u);
            }
        });
        vector<int> a(n), b(m);
        dfs(e, a, 0, -1);
        dfs(f, b, 0, -1);
        int A[2] = {(int)rgs::count(a, 0), (int)rgs::count(a, 1)};
        int B[2] = {(int)rgs::count(b, 0), (int)rgs::count(b, 1)};
        vector<int> ans(n);
        for (int i = 0; i < n; ++i)
            ans[i] = A[a[i]] + max(B[0], B[1]);
        return ans;

    }
};